package de.hauschild.gmltracer.tracer.impl.tier1;

import java.util.List;

import org.apache.commons.math.geometry.Vector3D;

import de.hauschild.gmltracer.tracer.Intersection;
import de.hauschild.gmltracer.tracer.Ray;
import de.hauschild.gmltracer.tracer.Shape;
import de.hauschild.gmltracer.tracer.SurfaceFunction;
import de.hauschild.gmltracer.tracer.impl.AbstractShape;

/**
 * The {@link Union} shape combines two {@link Shape Shapes} for building scenes.
 * 
 * @author Klaus Hauschild
 * @since 1.0.0
 * @deprecated Simple reference implementation. Use {@link CollectiveUnion} instead.
 */
@Deprecated
public class Union extends AbstractShape {

  private static final SurfaceFunction NOP_SUREFACE_FUNCTION = new NopSurfaceFunction();

  private final Shape first;
  private final Shape second;
  private AbstractShape lastIntersected;

  /**
   * Instantiates a new union.
   * 
   * @param theFirst
   *          the first
   * @param theSecond
   *          the second
   */
  public Union(final Shape theFirst, final Shape theSecond) {
    super(NOP_SUREFACE_FUNCTION);
    first = theFirst;
    second = theSecond;
    lastIntersected = null;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public SurfaceFunction getSurfaceFunction() {
    if (lastIntersected != null) {
      return lastIntersected.getSurfaceFunction();
    }
    return NOP_SUREFACE_FUNCTION;
  }

  @Override
  public Intersection intersectAfterIgnoration(final Ray ray, final List<Shape> shapesToIngore) {
    final Intersection firstIntersection = first.intersect(ray, shapesToIngore);
    final Intersection secondIntersection = second.intersect(ray, shapesToIngore);

    if (firstIntersection == null && secondIntersection == null) {
      lastIntersected = null;
      return null;
    } else if (firstIntersection != null && secondIntersection == null) {
      lastIntersected = (AbstractShape) first;
      return firstIntersection;
    } else if (firstIntersection == null && secondIntersection != null) {
      lastIntersected = (AbstractShape) second;
      return secondIntersection;
    } else {
      final double firstSquareLength = firstIntersection.getPoint().getX() * firstIntersection.getPoint().getX()
          + firstIntersection.getPoint().getY() * firstIntersection.getPoint().getY()
          + firstIntersection.getPoint().getZ() * firstIntersection.getPoint().getZ();
      final double secondSquareLength = secondIntersection.getPoint().getX() * secondIntersection.getPoint().getX()
          + secondIntersection.getPoint().getY() * secondIntersection.getPoint().getY()
          + secondIntersection.getPoint().getZ() * secondIntersection.getPoint().getZ();

      if (firstSquareLength < secondSquareLength) {
        lastIntersected = (AbstractShape) first;
        return firstIntersection;
      }
      lastIntersected = (AbstractShape) second;
      return secondIntersection;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Vector3D objectCoordinates(final Vector3D theIntersection) {
    if (lastIntersected != null) {
      return lastIntersected.objectCoordinates(theIntersection);
    }
    return null;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void rotateX(final double degrees) {
    first.rotateX(degrees);
    second.rotateX(degrees);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void rotateY(final double degrees) {
    first.rotateY(degrees);
    second.rotateZ(degrees);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void rotateZ(final double degrees) {
    first.rotateZ(degrees);
    second.rotateZ(degrees);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void scale(final double x, final double y, final double z) {
    first.scale(x, y, z);
    second.scale(x, y, z);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void translate(final double x, final double y, final double z) {
    first.translate(x, y, z);
    second.translate(x, y, z);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void uniformScale(final double scale) {
    first.uniformScale(scale);
    second.uniformScale(scale);
  }

}
